home *** CD-ROM | disk | FTP | other *** search
- Newsgroups: comp.sources.unix
- Subject: v15i048: Building custom Yellow Page Maps
- Approved: rsalz@uunet.UU.NET
-
- Submitted-by: Chuq Von Rospach <chuq@sun.com>
- Posting-number: Volume 15, Issue 48
- Archive-name: yp-quote
-
- [ It came in two pieces, so I repacked it. --r$ ]
- This toy application creates a map called 'quotes'. The program 'quote'
- will then access a random data element of this map and print it out.
- The source I've used for the data of quotes is the fortune data file,
- so this is essentially a Yellow Page based, distributed version of the
- fortune program.
-
- See the README for more details. This code is completely
- non-proprietary and was written using nothing more than my background
- in this stuff, the documentation and man pages. So it's completely
- non-proprietary and unrestricted. Feel free to pass it around as widely
- as you want -- it was written to teach me how to do this, and I make it
- available to help teach you.
-
- Have fun! comments, etc. to me!
-
- chuq, Sun Tech Support
- --------------------------------------
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 1 (of 1)."
- # Contents: Makefile README addpct.c quote.c quote.l quotedb.c
- # strfile.h unstr.c
- # Wrapped by rsalz@fig.bbn.com on Wed Jun 8 15:36:35 1988
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'Makefile' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'Makefile'\"
- else
- echo shar: Extracting \"'Makefile'\" \(356 characters\)
- sed "s/^X//" >'Makefile' <<'END_OF_FILE'
- X#
- X# Makefile for quotedb
- X#
- XCFLAGS= -g
- X
- Xall: addpct quote quotedb unstr
- X
- Xclean:
- X rm -f addpct quote quotedb unstr core *.o
- X
- Xaddpct: addpct.o
- X $(CC) $(CFLAGS) addpct.o -o addpct
- X
- Xquote: quote.o
- X $(CC) $(CFLAGS) quote.o -o quote
- X
- Xquotedb: quotedb.o
- X $(CC) $(CFLAGS) quotedb.o -o quotedb
- X
- Xunstr: unstr.o
- X $(CC) $(CFLAGS) unstr.o -o unstr
- X
- Xunstr.o: strfile.h
- END_OF_FILE
- if test 356 -ne `wc -c <'Makefile'`; then
- echo shar: \"'Makefile'\" unpacked with wrong size!
- fi
- # end of 'Makefile'
- fi
- if test -f 'README' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'README'\"
- else
- echo shar: Extracting \"'README'\" \(4755 characters\)
- sed "s/^X//" >'README' <<'END_OF_FILE'
- XDocumentation for the quote program, a toy application showing how to
- Xset up and use a custom Yellow Pages database.
- X
- XChuq Von Rospach
- XSun Tech Support
- X
- XRelease 1.0: May 2, 1988
- X
- X Manifest:
- X
- XMakefile
- X Builds everything of interest
- XREADME
- X This file
- Xaddpct.c
- X Takes a file of quotes separated by blank lines and converts
- X them into the fortune file format separated by a line containing
- X '%%' -- used to convert Moriarty quotes to fortune quotes (and
- X if you don't know what that means, ignore this)
- Xquote.c
- X The user program. Looks up random quotes from the quotes Yellow
- X Pages database.
- Xquotedb.c
- X This program reads a fortune source file and puts it into a format
- X usable by makedbm to create a Yellow Pages map.
- Xstrfile.h
- Xunstr.c
- X These public domain programs by Ken Arnold read a compiled fortune
- X file (for instance, /usr/games/lib/fortunes.dat) and turn it into
- X a source file readable by man or the quotedb program.
- X
- X What this stuff is:
- X
- XThe quote program is a toy application designed to show how to implement
- Xyour own custom Yellow Pages maps under SunOS 3.x or 4.0. YP maps are a
- Xgood, general purpose distributed database. Because of a dearth of good
- Xdocumentation on it, few customer databases have been developed for it. This
- Xprogram is aimed at clearing up some of the confusion of how to generate
- Xmaps and then access the data in them.
- X
- XYellow Page maps are created by the "makedbm" program. The format of the
- Xthe input data is simple, consisting of a key and data:
- X
- X key<whitespace>data<newline>
- X
- XOnce data is in the map, it can then be pulled out by doing a lookup on the
- Xgiven key. At the user level, that is done by:
- X
- X ypmatch key mapname
- X
- Xquote.c shows how to do it from a programmatic view.
- X
- XHow to Set this up:
- X
- X o Compile unstr.c
- X o use unstr.c to de-compile /usr/games/lib/fortunes.dat (note:
- X this requires root, as does all the YP stuff....)
- X o cp the created file to /var/yp/quotes (/usr/etc/yp/quotes
- X under 3.X)
- X o compile quotedb.c, and copy it into /var/yp/quotedb
- X o Add the following rule to /var/yp/Makefile (this will require
- X minor changes, mostly pathnames, to go into
- X /usr/etc/yp/Makefile. Changes should be obvious
- X in context of the existing YP Makefile)
- X
- X--------- /var/yp/Makefile ---------------
- X# Add quotes to the all rule
- Xall: passwd group hosts ethers networks rpc services protocols \
- X netgroup bootparams aliases publickey netid c2secure netmasks \
- X stars ypservers quotes
- X
- Xquotes.time: $(YPDBDIR)/quotes
- X -@if [ -f $(YPDBDIR)/quotes ]; then \
- X quotedb < $(YPDBDIR)/quotes | $(MAKEDBM) - \
- X $(YPDBDIR)/$(DOM)/quotes; \
- X touch quotes.time; \
- X echo "update quotes"; \
- X if [ ! $(NOPUSH) ]; then \
- X $(YPPUSH) quotes; \
- X echo "pushed quotes"; \
- X else \
- X : ; \
- X fi \
- X else \
- X echo "couldn't find $(YPDBDIR)/quotes"; \
- X fi
- X
- X# Add to the dependency list
- Xquotes: quotes.time
- X
- X-------- end /var/yp/Makefile -----------
- X
- X o cd into /var/yp and run 'make'
- X o if all goes well, the map should exist. "ypwhich -m" should say
- X something like:
- X quotes plaid # replace plaid with your yp server name
- X "ypmatch MAX quotes" should print out a number, and
- X "ypmatch 15 quotes" should print out a quote.
- X
- X o compile quote.c. Try running quote. It should print a quote.
- X
- X Final Comments:
- X
- XNote that quote doesn't support any of the flags that the fortune program
- Xhas, such as long, short, obscene, etc. Other than that, this makes a good
- Xreplacement for keeping /usr/games on the disk or NFS mounting /usr/games
- Xif all you care about is running fortune when you log in.
- X
- XPlease note that the program unstr is a public domain program written by Ken
- XArnold to unpack the public domain fortune's data files. This format happens
- Xto also work with the SunOS fortune files (not surprising, since Ken wrote
- Xthe original fortune, which we've adopted).
- X
- XAlso, all of this code was written from the man pages and documentation, not
- Xfrom any proprietary source. It is, therefore, not proprietary to either Sun
- Xor AT&T source code agreements, so you can pass it around as widely as you
- Xwant. That's the point, of course -- this is designed to be educational.
- X
- XNote that because of inherent (but very large) limitations of the ndbm()
- Xpackage, it is possible to build a data set too large for YP to handle.
- XIf you get that, you'll see errors from makedbm and the map won't create
- Xor update. All you can do is make the dataset smaller. The only place I've
- Xseen this is with my special, 6000 entry quote file, but you've been warned.
- XAnd no, I don't distribute my quote file -- it's too large.
- X
- Xcomments, thoughts, feedback, criticism and money are all welcome.
- END_OF_FILE
- if test 4755 -ne `wc -c <'README'`; then
- echo shar: \"'README'\" unpacked with wrong size!
- fi
- # end of 'README'
- fi
- if test -f 'addpct.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'addpct.c'\"
- else
- echo shar: Extracting \"'addpct.c'\" \(356 characters\)
- sed "s/^X//" >'addpct.c' <<'END_OF_FILE'
- X/*
- X * This takes a file with quotes delimited by a blank line (typically
- X * a moriarty quote file) and turns it into a %% delimited file that
- X * can be imported into a fortune database
- X *
- X * chuq von rospach
- X */
- X
- X#include <stdio.h>
- X
- Xmain()
- X{
- X char line[BUFSIZ];
- X
- X while (gets(line))
- X if (strlen(line))
- X puts(line);
- X else
- X printf("%%%%\n");
- X}
- END_OF_FILE
- if test 356 -ne `wc -c <'addpct.c'`; then
- echo shar: \"'addpct.c'\" unpacked with wrong size!
- fi
- # end of 'addpct.c'
- fi
- if test -f 'quote.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'quote.c'\"
- else
- echo shar: Extracting \"'quote.c'\" \(1520 characters\)
- sed "s/^X//" >'quote.c' <<'END_OF_FILE'
- X#include <stdio.h>
- X#include <rpcsvc/ypclnt.h>
- X
- X#define MAXLEN 4096
- X#define randint(maxval) ((random() % (maxval)) + 1)
- X
- Xchar dom_name[BUFSIZ];
- X
- Xmain()
- X{
- X char *quotebuf;
- X int quotelen;
- X char *maxbuf;
- X int maxlen;
- X int maxnum = 0;
- X int quotenum = 0;
- X char *c;
- X char *index();
- X
- X srandom(getpid()); /* initialize random numbers */
- X
- X /* who are we? */
- X if (getdomainname(dom_name, BUFSIZ)) {
- X fprintf(stderr, "No domainname set\n");
- X exit(1);
- X }
- X
- X /* Get the highest quote in the system */
- X get_match("MAX", &maxbuf, &maxlen);
- X maxnum = atoi(maxbuf);
- X
- X /* Generate a random number between 1 and maxnum */
- X quotenum = randint(maxnum);
- X if (quotenum < 0 || quotenum > maxnum) {
- X fprintf(stderr, "Illegal randint value!\n");
- X exit(1);
- X }
- X
- X /* now grab that quote */
- X sprintf(maxbuf,"%d",quotenum);
- X get_match(maxbuf, "ebuf, "elen);
- X
- X /* turn all ^A characters to newlines.
- X * turn all ^B characters to tabs.
- X * needed to allow proper insertion into a yp database, since makedbm
- X * uses both as delimiters.
- X */
- X while ((c = index(quotebuf,'\001')))
- X *c = '\n';
- X
- X while ((c = index(quotebuf,'\002')))
- X *c = '\t';
- X
- X /* print it out */
- X printf("%s",quotebuf);
- X}
- X
- X/* get the largest quote from key MAX */
- X
- Xget_match(key, retval, retlen)
- X char *key;
- X char **retval;
- X int *retlen;
- X{
- X
- X if (yp_match(dom_name, "quotes", key, strlen(key), retval, retlen)) {
- X fprintf(stderr, "error in ypmatch\n");
- X exit(1);
- X }
- X}
- END_OF_FILE
- if test 1520 -ne `wc -c <'quote.c'`; then
- echo shar: \"'quote.c'\" unpacked with wrong size!
- fi
- # end of 'quote.c'
- fi
- if test -f 'quote.l' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'quote.l'\"
- else
- echo shar: Extracting \"'quote.l'\" \(1457 characters\)
- sed "s/^X//" >'quote.l' <<'END_OF_FILE'
- X.TH QUOTE 6
- X.SH NAME
- Xquote - read quotes from a Yellow Pages Database
- X.SH SYNOPSIS
- X.B quote
- X.br
- X.B quotedb
- X.SH DESCRIPTION
- X.I Quote
- Xis a toy application designed to show how to create and access a custom
- XYellow Pages database.
- XIt creates a Yellow Pages version of the program
- Xfortune.
- X.PP
- X.I Quote
- Xis the user program.
- XIt reads the Yellow Pages database "quotes" to get a random quote
- Xout of it.
- X.PP
- X.I Quotedb
- Xis the program that takes a "fortune" style source file and turns it into
- Xa format that can be fed to
- X.I makedbm
- Xto create the Yellow Pages database.
- X.PP
- XSee the README and the source for the grotty details of how to modify the
- XYP Makefile and how all this stuff fits together.
- X.SH AUTHOR
- XChuq Von Rospach, Sun Microsystems Tech Support (chuq@sun.COM)
- X.SH DIAGNOSTICS
- XGenerally self-documenting, as they say. At least in theory.
- X.PP
- XError messages from
- X.I makedbm
- Xmay not be as clear as you might hope.
- X.SH BUGS
- XThere are limits to the amount of data that can be shoved in a ndbm(3)
- Xdatabase.
- XLarge text based items (like quotes) will fill up a database faster than
- Xsmall ones.
- XSince YP uses ndbm(3) for internal storage, this means you might
- Xget creation errors on very large fortune files.
- XIf you get them, all you can do is shrink the data-set. In all practical
- Xcases,
- Xthis is probably not a problem.
- XI had to build an extremely large quotes file to find this out (the hard
- Xway, of course).
- XThanks to moriarty for making this bug findable.
- X
- END_OF_FILE
- if test 1457 -ne `wc -c <'quote.l'`; then
- echo shar: \"'quote.l'\" unpacked with wrong size!
- fi
- # end of 'quote.l'
- fi
- if test -f 'quotedb.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'quotedb.c'\"
- else
- echo shar: Extracting \"'quotedb.c'\" \(878 characters\)
- sed "s/^X//" >'quotedb.c' <<'END_OF_FILE'
- X#include <stdio.h>
- X
- X#define MAXLEN 450
- X
- Xchar quotebuf[MAXLEN];
- Xchar line[MAXLEN];
- Xint numq = 0;
- X
- Xchar *strcat();
- Xchar *strcpy();
- X
- Xmain()
- X{
- X
- X char *c, *index();
- X int endit = 0;
- X
- X while (gets(line)) {
- X if (line[0] == '%' && (line[1] == '%' || line[1] == '-')) {
- X
- X if (strlen(quotebuf)) {
- X numq++;
- X
- X /*
- X * mark all newlines and tabs with special character flags so
- X * you don't confuse makedbm
- X */
- X
- X while ((c = index(quotebuf, '\n')))
- X *c = '\001';
- X
- X while ((c = index(quotebuf, '\t')))
- X *c = '\002';
- X
- X printf("%d\t%s\n", numq, quotebuf);
- X strcpy(quotebuf, "");
- X }
- X } else {
- X
- X if ((strlen(line) + strlen(quotebuf)) > MAXLEN) {
- X/* fprintf(stderr, "\nLong quote:\n%s\n", quotebuf); */
- X strcpy(quotebuf, "");
- X } else {
- X strcat(quotebuf, line);
- X strcat(quotebuf, "\001");
- X }
- X }
- X }
- X printf("MAX\t%d\n", numq);
- X}
- END_OF_FILE
- if test 878 -ne `wc -c <'quotedb.c'`; then
- echo shar: \"'quotedb.c'\" unpacked with wrong size!
- fi
- # end of 'quotedb.c'
- fi
- if test -f 'strfile.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'strfile.h'\"
- else
- echo shar: Extracting \"'strfile.h'\" \(627 characters\)
- sed "s/^X//" >'strfile.h' <<'END_OF_FILE'
- X/* @(#)strfile.h 1.2 (Berkeley) 5/14/81 */
- X# ifndef __STRFILE__
- X
- X# define __STRFILE__
- X
- X# include <sys/types.h>
- X
- X# define MAXDELIMS 3
- X
- X/*
- X * bits for flag field
- X */
- X
- X# define STR_RANDOM 0x1
- X# define STR_ORDERED 0x2
- X
- Xtypedef struct { /* information table */
- X unsigned long str_numstr; /* # of strings in the file */
- X unsigned long str_longlen; /* length of longest string */
- X unsigned long str_shortlen; /* length of shortest string */
- X long str_delims[MAXDELIMS]; /* delimiter markings */
- X off_t str_dpos[MAXDELIMS]; /* delimiter positions */
- X short str_flags; /* bit field for flags */
- X} STRFILE;
- X
- X# endif __STRFILE__
- END_OF_FILE
- if test 627 -ne `wc -c <'strfile.h'`; then
- echo shar: \"'strfile.h'\" unpacked with wrong size!
- fi
- # end of 'strfile.h'
- fi
- if test -f 'unstr.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'unstr.c'\"
- else
- echo shar: Extracting \"'unstr.c'\" \(3701 characters\)
- sed "s/^X//" >'unstr.c' <<'END_OF_FILE'
- X# include <stdio.h>
- X# include <ctype.h>
- X# include "strfile.h"
- X
- X# define TRUE 1
- X# define FALSE 0
- X
- X/*
- X * This program un-does what "strfile" makes, thereby obtaining the
- X * original file again. This can be invoked with the name of the output
- X * file, the input file, or both. If invoked with only a single argument
- X * ending in ".dat", it is pressumed to be the input file and the output
- X * file will be the same stripped of the ".dat". If the single argument
- X * doesn't end in ".dat", then it is presumed to be the output file, and
- X * the input file is that name prepended by a ".dat". If both are given
- X * they are treated literally as the input and output files.
- X *
- X * Ken Arnold Aug 13, 1978
- X */
- X
- X# define DELIM_CH '-'
- X
- Xchar Infile[100], /* name of input file */
- X Outfile[100], /* name of output file */
- X Delimch = '%'; /* delimiter character */
- X
- Xshort Oflag = FALSE; /* use order of initial table */
- X
- XFILE *Inf, *Outf;
- X
- Xchar *rindex(), *malloc(), *strcat(), *strcpy();
- X
- Xmain(ac, av)
- Xint ac;
- Xchar **av;
- X{
- X register int c;
- X register int nstr, delim;
- X static STRFILE tbl; /* description table */
- X
- X getargs(ac, av);
- X if ((Inf = fopen(Infile, "r")) == NULL) {
- X perror(Infile);
- X exit(-1);
- X /* NOTREACHED */
- X }
- X if ((Outf = fopen(Outfile, "w")) == NULL) {
- X perror(Outfile);
- X exit(-1);
- X /* NOTREACHED */
- X }
- X (void) fread((char *) &tbl, sizeof tbl, 1, Inf);
- X if (Oflag) {
- X order_unstr(&tbl);
- X exit(0);
- X /* NOTREACHED */
- X }
- X nstr = tbl.str_numstr;
- X (void) fseek(Inf, (off_t) (sizeof (off_t) * (nstr + 1)), 1);
- X delim = 0;
- X nstr = 0;
- X while ((c = getc(Inf)) != EOF)
- X if (c != '\0')
- X putc(c, Outf);
- X else if (nstr != tbl.str_numstr - 1)
- X if (++nstr == tbl.str_delims[delim]) {
- X fprintf(Outf, "%c-\n", Delimch);
- X delim++;
- X }
- X else
- X fprintf(Outf, "%c%c\n", Delimch, Delimch);
- X exit(0);
- X /* NOTREACHED */
- X}
- X
- Xgetargs(ac, av)
- Xregister int ac;
- Xregister char *av[];
- X{
- X register int i;
- X register char *sp;
- X register int j;
- X register short bad;
- X
- X bad = 0;
- X for (i = 1; i < ac; i++) {
- X if (av[i][0] != '-') {
- X (void) strcpy(Infile, av[i]);
- X if (i + 1 >= ac) {
- X (void) strcpy(Outfile, Infile);
- X if ((sp = rindex(av[i], '.')) &&
- X strcmp(sp, ".dat") == 0)
- X Outfile[strlen(Outfile) - 4] = '\0';
- X else
- X (void) strcat(Infile, ".dat");
- X }
- X else
- X (void) strcpy(Outfile, av[i + 1]);
- X break;
- X }
- X else if (av[i][1] == '\0') {
- X printf("usage: unstr [-o] [-cC] datafile[.dat] [outfile]\n");
- X exit(0);
- X /* NOTREACHED */
- X }
- X else
- X for (sp = &av[i][1]; *sp != '\0'; sp++)
- X switch (*sp) {
- X case 'o': /* print out in seekptr order */
- X Oflag++;
- X break;
- X case 'c': /* new delimiting char */
- X if ((Delimch = *++sp) == '\0') {
- X --sp;
- X Delimch = *av[++i];
- X }
- X if (!isascii(Delimch)) {
- X fprintf(stderr,
- X "bad delimiting character: 0x%x\n",
- X Delimch);
- X bad++;
- X }
- X break;
- X default:
- X fprintf(stderr, "unknown flag: '%c'\n",
- X *sp);
- X bad++;
- X break;
- X }
- X }
- X if (bad) {
- X printf("use \"%s -\" to get usage\n", av[0]);
- X exit(-1);
- X }
- X}
- X
- Xorder_unstr(tbl)
- XSTRFILE *tbl;
- X{
- X register int i, c;
- X register int delim;
- X register off_t *seekpts;
- X
- X seekpts = (off_t *) malloc(sizeof *seekpts * tbl->str_numstr); /* NOSTRICT */
- X if (seekpts == NULL) {
- X perror("malloc");
- X exit(-1);
- X /* NOTREACHED */
- X }
- X (void) fread((char *) seekpts, sizeof *seekpts, (int) tbl->str_numstr,
- X Inf);
- X delim = 0;
- X for (i = 0; i < tbl->str_numstr; i++, seekpts++) {
- X if (i != 0)
- X if (i == tbl->str_delims[delim]) {
- X fputs("%-\n", Outf);
- X delim++;
- X }
- X else
- X fputs("%%\n", Outf);
- X (void) fseek(Inf, *seekpts, 0);
- X while ((c = getc(Inf)) != '\0')
- X putc(c, Outf);
- X }
- X}
- END_OF_FILE
- if test 3701 -ne `wc -c <'unstr.c'`; then
- echo shar: \"'unstr.c'\" unpacked with wrong size!
- fi
- # end of 'unstr.c'
- fi
- echo shar: End of archive 1 \(of 1\).
- cp /dev/null ark1isdone
- MISSING=""
- for I in 1 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have the archive.
- rm -f ark[1-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
- --
- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.
-